package com.longlong.orm;

import com.longlong.orm.annotation.Delete;
import com.longlong.orm.annotation.Insert;
import com.longlong.orm.annotation.Select;
import com.longlong.orm.annotation.Update;
import com.longlong.pool.BusinessException;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class InvocationHandlerImpl implements InvocationHandler {

    private SqlSession sqlSession = new SqlSession();

    /**
     * @param proxy  代理对象
     * @param method 被代理对象的方法
     * @param args   方法参数
     * @return
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 1. 通过方法的注解获取 sql 语句
        //    获取方法上面的注解
        Annotation an = method.getAnnotations()[0];
        //    获取找到这个注解的类型
        Class<?> type = an.annotationType();
        //    获取注解里面的 value 方法
        Method valueMethod = type.getDeclaredMethod("value");
        //    调用 value 方法获取 SQL
        String sql = (String) valueMethod.invoke(an);

        // 2. 获取参数
        Object param = args == null ? null : args[0];

        // 3. 执行
        //    根据 type 判断调用的方法
        if (type == Insert.class) {
            sqlSession.insert(sql, param);
        } else if (type == Delete.class) {
            sqlSession.delete(sql, param);
        } else if (type == Update.class) {
            sqlSession.update(sql, param);
        } else if (type == Select.class) {
            // 查询操作 有两种情况
            // 根据返回值类型判断 查询单条记录 or 查询多条记录
            Class<?> methodReturnTypeClass = method.getReturnType();
            if (methodReturnTypeClass == List.class) {
                // 查询多条
                // 返回值的具体类型(java.util.List<domain.Student>)
                // 解析 methodReturnTypeClass 里面的那个泛型
                // 现在需要解析 List 里面的泛型
                // method.getReturnType() 返回一个 Class 对象，表示方法的原始返回类型
                // method.getGenericReturnType() 返回一个 Type 对象
                Type returnType = method.getGenericReturnType();
                // returnType 可能是 Class、ParameterizedType、GenericArrayType 或 TypeVariable 的实例
                // 如果返回类型是 ParameterizedType，则表示方法返回一个带有泛型参数的类或接口
                ParameterizedType realReturnType = (ParameterizedType) returnType;
                // 获取到泛型类 []
                Type[] patternTypes = realReturnType.getActualTypeArguments();
                Type patternType = patternTypes[0];
                // 此时 patternType 是 Class<?> 的实例
                Class<?> resultType = (Class<?>) patternType;
                return sqlSession.selectList(sql, param, resultType);
            } else {
                // 查询单条
                return sqlSession.selectOne(sql, param, methodReturnTypeClass);
            }
        } else {
            throw new BusinessException("注解解析错误");
        }
        return null;
    }

}
